﻿using System;
using System.Globalization;
using System.Linq;
using Cpuss.Strategies.Properties;

namespace Cpuss.Strategies
{

    /// <summary>
    /// Priority First strategy.
    /// </summary>
    /// <remarks>
    /// The processes in the ready queue with the higher priorities are given preference when selecting a process
    /// to utilize the CPU.
    /// </remarks>
    public class PriorityFirst : IStrategy
    {

        private readonly int _pollTime;

        /// <summary>
        /// Creates and initializes a new instance of the PF strategy.
        /// </summary>
        /// <param name="pollTime">Poll time.</param>
        /// <exception cref="ArgumentOutOfRangeException"><strong>pollTime</strong> is less than <strong>1</strong>.</exception>
        public PriorityFirst(int pollTime)
        {
            if (pollTime < 1)
            {
                throw new ArgumentOutOfRangeException(Resources.PollTimeGreaterThanZero);
            }

            _pollTime = pollTime;
        }

        /// <summary>
        /// Executes the processes in <see cref="Runner.ProcessLoad"/> in priority first order.
        /// </summary>
        /// <param name="runner">Runner to use as execution enviroment.</param>
        public void Execute(Runner runner)
        {
            ProcessLoad readyQueue = new ProcessLoad(runner.ProcessLoad);

            while (readyQueue.Count > 0)
            {
                try
                {
                    // select the (first) process in readyQueue with the highest priority
                    Process p = readyQueue.Where(x => x.ArrivalTime <= runner.Time).OrderByDescending(x => x.Priority).First();
                    runner.UtilizeCpu(p, _pollTime);
                    if (Process.IsComplete(p))
                    {
                        runner.LogProcessMetrics(p);
                        readyQueue.Remove(p);
                    }
                }
                catch (InvalidOperationException)
                {
                    runner.SkipIdleCpuTime();
                }
            }
        }

        /// <summary>
        /// Returns a <see cref="string"/> that represents the current <see cref="object"/>.
        /// </summary>
        /// <returns>String representation of object.</returns>
        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture, "Priority First (Poll Time = {0})", _pollTime);
        }

    }

}
